package com.qtong.service.impl;

import com.qtong.entity.cinemas.Cinemas;
import com.qtong.entity.movies.Movie;
import com.qtong.entity.screenings.Screening;
import com.qtong.service.AssignmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.*;

@Service
public class AssignmentServiceImpl implements AssignmentService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public List<Cinemas> findCinemasByCity(String city) {
    // Combine OR conditions into a single orOperator to avoid multiple $or in the same Criteria
    Criteria c = new Criteria().orOperator(
        Criteria.where("region.city").is(city),
        Criteria.where("city").is(city),
        Criteria.where("address").regex(city)
    );
    Query q = new Query(c);
    return mongoTemplate.find(q, Cinemas.class);
    }

    @Override
    public List<Movie> findMoviesNowPlaying(String cinemaId) {
        Query q = new Query(Criteria.where("cinemaId").is(cinemaId).and("showTime").gte(Date.from(Instant.now())));
        List<Screening> screenings = mongoTemplate.find(q, Screening.class);
        Set<String> mids = new HashSet<>();
        for (Screening s : screenings) mids.add(s.getMovieId());
        if (mids.isEmpty()) return Collections.emptyList();
        Query mq = new Query(Criteria.where("movieId").in(mids));
        return mongoTemplate.find(mq, Movie.class);
    }

    @Override
    public List<Cinemas> findNearby(double lng, double lat, int limit) {
        NearQuery near = NearQuery.near(new Point(lng, lat), Metrics.KILOMETERS).maxDistance(50);
        GeoResults<Cinemas> res = mongoTemplate.geoNear(near.limit(limit), Cinemas.class);
        List<Cinemas> list = new ArrayList<>();
        if (res != null) res.forEach(r -> list.add(r.getContent()));
        return list;
    }

    @Override
    public List<Movie> findMoviesByDirector(String director) {
        Query q = new Query(Criteria.where("director").is(director));
        return mongoTemplate.find(q, Movie.class);
    }

    @Override
    public List<Movie> findMoviesByActor(String actor) {
        Query q = new Query(Criteria.where("actors").in(actor));
        return mongoTemplate.find(q, Movie.class);
    }
}
